gui: the format menu is one width, the Remove button is a button, and macOS gets an icon - #16
Merged
donislawdev merged 2 commits intoAug 28, 2026
Conversation
Both reported by the owner from the running window, and in both cases the cause the measurement found is not the one the report describes. The format menu was 140 px on the single batch screen and 98 px on the presets screen and in a row of an archive's contents, for the same twenty formats. That looked like the screens disagreeing and was an order dependency. parts.menuWidth takes the widest thing a menu can show, which includes its placeholder, and the toolkit substitutes its own default placeholder while the renderer is made - fyne v2.8.1 widget/select.go line 94, read in the pinned module. So a menu that something had already selected a value on was measured against 76 px of "(Select one)", and an identical one built cold was measured against 34 px of "targz". The narrow ones then could not show the placeholder they had been given, and a fresh row of an archive's contents drew "(Select ...". A menu is now never narrower than parts.NumericWidth, which is the narrowest box these screens draw. That is the owner's report stated as a relationship rather than as a number: nothing was cut off on the presets screen, and what was wrong is that one setting was 140 px on one screen and 98 on another because of how long the words "pdf" and "targz" happen to be. Rejected on the way, before the commit: a call to MinSize before measuring, so the toolkit would have filled its default placeholder in first. It cannot change an answer - that string needs 139.91 px and the floor gives 140 - and a line that cannot change an answer is not a defence. The Remove button ending a row of an archive's contents was 197.50 x 63.16 px for a word needing 67.92 x 32: a quarter of the form wide and as tall as a label and a control together, so it read as a panel with a word in the middle. parts.Row shares the width out in equal columns, which is what a field wants and what anything else gets whether it wants it or not. parts.BesideFields keeps something that is not a field out of that arithmetic and puts it on the line the controls are on. Three guards, three mutations, each went red. The stored screens were regenerated and the diff read: every changed line is a width, except six in recipe-contents.xml which are the two containers now around that button. The picture of that row has been in testdata/screens since the day the state existed, and the pixel guard compared it on every run. A stored picture proves nothing changed, never that nothing is wrong. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
O154, reported by the owner. The program became a .app in the release before this one, because that is the only shape a notarisation ticket attaches to, and a bundle with no icon is drawn by the Finder and the Dock as a blank sheet of paper - which is what a program the system knows nothing about looks like. The note in that observation said this was one command on the runner with sips and iconutil, "because the release runner is a Mac anyway". That premise is false and reading the workflow was the first thing done here: the command line archives are cross compiled on ubuntu-latest and that is where make_app_bundle is called, so Apple's tools are not there. Only the window job runs on a Mac. So the icon is a file in the repository, written by tools/appicon.py --icns. It assembles the container itself - a header and then one chunk per type, each holding a PNG drawn at its own size rather than scaled up from one master. Ten types, because macOS asks for a point size and a scale: 16, 32 twice, 64, 128, 256 twice, 512 twice and 1024. Pillow's own ICNS writer was tried first and is not usable here: it writes eight of the ten, leaving out the two a screen without Retina asks for, and it upsamples a 256 px master to 1024. Verified with Apple's own tool on a real Mac, not assumed: iconutil --convert iconset exits 0 and hands back all ten entries at those pixel sizes. The script was then run there end to end on a dummy binary - Resources/icon.icns is in the bundle and PlistBuddy reads CFBundleIconFile out of the plist. The script refuses when the icon file is missing rather than carrying on. A bundle without one builds, signs, notarises and staples exactly like a bundle with one, so nothing between the build and somebody's screen would say a word. The rounded square variant, by the owner's decision: every icon in the Dock is a rounded square of the same size, so a free floating shape reads as smaller and foreign there. Windows and Linux keep the plain one. Two guards. The bundle one is proven by mutation. The one that reads the icon's bytes is proven by probe and says why in the list: it reads a committed binary asset, so no substitution in a .go or .py file reaches it. Broken by hand three ways - a size cut out, a picture resized, a lying length in the header - red each time, and put back byte for byte, checked by hash. What this does NOT prove, and it is in O156: nobody has seen the icon on a screen. qlmanage over SSH never finishes, because Quick Look needs a session with a display, which is the same wall that leaves D4 open for the window on macOS. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
donislawdev
deleted the
gui/the-format-menu-is-one-width-and-the-mac-gets-an-icon
branch
August 28, 2026 19:39
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three things the owner reported from the running window on 2026-08-28. In two of the three the cause the measurement found is not the one the report describes.
The format menu was two different widths
140 px on the single batch screen, 98 px on the presets screen and in a row of an archive's contents, for the same twenty formats.
That looked like the screens disagreeing and was an order dependency.
parts.menuWidthtakes the widest thing a menu can show, which includes its placeholder, and the toolkit substitutes its own default placeholder while the renderer is made -fyne v2.8.1 widget/select.go:94, read in the pinned module. So a menu something had already selected a value on was measured against 76 px of(Select one), and an identical one built cold against 34 px oftargz.The narrow ones then could not show the placeholder they had been given: a fresh row of an archive's contents drew
(Select ..., cut off mid word, in the box that exists to show it.A menu is now never narrower than
parts.NumericWidth, the narrowest box these screens draw. That states the report as a relationship rather than as a number - nothing was cut off on the presets screen, and what was wrong is that one setting was 140 px on one screen and 98 on another because of how long the wordspdfandtargzhappen to be.Rejected on the way, before the commit: a
MinSizecall before measuring, so the toolkit would have filled its placeholder in first. It cannot change an answer - that string needs 139.91 px and the floor gives 140 - and a line that cannot change an answer is not a defence.The Remove button was a panel
197.50 x 63.16 pxfor a word needing67.92 x 32: a quarter of the form wide and as tall as a label and a control together.parts.Rowshares the width out in equal columns, which is what a field wants and what anything else gets whether it wants it or not.parts.BesideFieldskeeps something that is not a field out of that arithmetic and puts it on the line the controls are on.The picture of that row has been in
testdata/screenssince the day the state existed, and the pixel guard compared it on every run. A stored picture proves nothing changed, never that nothing is wrong.macOS had no icon
The program became a
.appin the last release, and a bundle with no icon is drawn by the Finder and the Dock as a blank sheet of paper.The observation said this was one command on the runner with
sipsandiconutil, "because the release runner is a Mac anyway". False, and reading the workflow was the first thing done: the command line archives are cross compiled onubuntu-latestand that is where the bundle is put together. So the icon is a file in the repository, written bytools/appicon.py --icns- ten types, each a PNG drawn at its own size rather than scaled up from one master. Pillow's ICNS writer was tried and is not usable: eight of the ten types, and it upsamples 256 px to 1024.Verified with Apple's own tool on a real Mac:
iconutil --convert iconsetexits 0 and hands back all ten entries at the right pixel sizes, and the script was run there end to end on a dummy binary. The script refuses when the icon is missing, because a bundle without one signs, notarises and staples exactly like one with an icon.Not proven, and it is written down as O156: nobody has seen the icon on a screen.
qlmanageover SSH never finishes - Quick Look needs a session with a display, the same wall that leavesD4open for the window on macOS.Guards
Five, four proven by mutation and each went red. The fifth reads the icon's committed bytes, so no substitution in a
.goor.pyfile reaches it - it is onprovenByProbe, broken by hand three ways (a size cut out, a picture resized, a lying length in the header) and put back byte for byte, checked by hash.Stored screens regenerated and the diff read: every changed line is a width, except six in
recipe-contents.xmlwhich are the two containers now around that button.Full suite green. New probe
tools/probes/menuwidthprints every laid out width per screen, which is what separated the two causes.